import {
  Component,
  OnInit,
  ViewEncapsulation,
  ChangeDetectionStrategy,
  NgZone,
  ChangeDetectorRef,
  Input,
  OnChanges,
  SimpleChanges,
  Renderer2,
  ElementRef,
} from '@angular/core';
import { forEach as _forEach, filter as _filter } from 'lodash';
import { InputBoolean, flatMap as lvFlatMap, ResizeObserverService, I18NService, BaseTreeNode } from '../core/api';
import { DatatableComponent } from './datatable.component';
import { TreeTableNode, TreeTableNode as TreeNode } from './interface';
import { DatatableService } from './datatable.service';

const treeTableHostConfig = {
  class: 'lv-treetable',
  '[class.lv-table]': 'true',
  '[class.lv-table-default]': 'lvSize === "default"',
  '[class.lv-table-large]': 'lvSize === "large"',
  '[class.lv-table-small]': 'lvSize === "small"',
  '[class.lv-table-stripe]': 'lvStripe',
};

@Component({
  selector: 'lv-treetable',
  templateUrl: './datatable.component.html',
  styles: [],
  providers: [DatatableService],
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: treeTableHostConfig,
})
export class TreetableComponent extends DatatableComponent implements OnInit, OnChanges {
  // 输入输出属性
  @Input() @InputBoolean() lvSelectionAssociate = true; // 选择关联，选中是否关联父子选中

  traversal = true; // 数据处理是否遍历子项
  // 外部可访问变量
  originSelectionData: TreeNode[]; // 记录源比较项

  // 内部变量
  private _unfoldData: Map<any, TreeNode>; // 平铺的data
  private _unfoldSelectionData: Map<any, TreeNode>; // 平铺的selectiondata
  private _originSelectionDataChanged: boolean = false; // 判断是否lvSelectionData设置的标记

  constructor(
    public ngZone: NgZone,
    public _cdr: ChangeDetectorRef,
    public datatableService: DatatableService,
    public _renderer: Renderer2,
    public resizeObserverService: ResizeObserverService,
    public elementRef: ElementRef,
    public i18n: I18NService,
  ) {
    super(ngZone, _cdr, datatableService, _renderer, resizeObserverService, elementRef, i18n);
    this.datatableService.setParentComponent(this);
  }

  ngOnInit(): void {
    super.ngOnInit();
  }

  // 判断当前行是否在当前渲染列表中
  getRowInRender(source: any): boolean {
    return this.getUnfoldRenderData().includes(source);
  }

  // 通过data找到父级data
  getParentData(source: TreeNode): BaseTreeNode {
    return (this._unfoldData.get(this.result(source)) || { parent: null }).parent;
  }

  // 全选时traverse为false，只遍历子集不遍历后代，半选时traverse为true，需要遍历所有后代
  resultToDataMap(source: any[], traverse: boolean = false): Map<any, any> {
    return lvFlatMap(source, this.lvCompareWith, traverse);
  }

  initSelectionData(): void {
    this.originSelectionData = [...(this.lvData || [])];
    this.setUnfoldSelectionData(this.originSelectionData);
  }

  getParentSelectionData(source: TreeNode): BaseTreeNode {
    return (this._unfoldSelectionData.get(this.result(source)) || { parent: null }).parent;
  }

  setUnfoldSelectionData(source: TreeNode[]): void {
    this._unfoldSelectionData = new Map();
    this.setUnfoldData(source, this._unfoldSelectionData);
  }

  // 切换选中项并触发change
  _toggleSelection(source: any, selected: boolean): void {
    if (source.disabled) {
      return;
    }
    this.toggleSelectionByStatus(source, selected);
  }

  // 选中当前行
  toggleSelection<T>(source: T): void {
    super.toggleSelection(source, false);

    // 祖先后代
    this.toggleGenerationSelection(source);

    // 更新selection
    this.updateSelection();
  }

  /**
   * 行选中有联动关系时（树表），行选中影响父子行
   * @param source 选中项
   */
  toggleGenerationSelection(source: any): void {
    if (!this.lvSelectionAssociate || source.disabled) {
      return;
    }

    this._toggleDescendantsSelection(source);
    this._toggleAncestorSelection(source);
  }

  // 表头默认判断的全选列表，即渲染的所有项 排除disabled
  getUnfoldRenderData(): TreeTableNode[] {
    const renderDataMap = this.getRenderDataMap(this.renderData);
    const data = Array.from(renderDataMap.values());
    return data.filter((item): boolean => !item.disabled);
  }

  // 获取当前渲染项选中项-当前渲染
  getRenderSelection(): any {
    const renderDataMap = this.getRenderDataMap(this.renderData);
    const selected = this.getSelection();
    return _filter(selected, (item): boolean => renderDataMap.has(this.result(item)));
  }

  setUnfoldData(source: TreeNode[], target: Map<any, TreeNode>, parent?: TreeNode): void {
    _forEach(source, (item): void => {
      target.set(this.result(item), { ...item, parent });
      this.setUnfoldData(item.children, target, item);
    });
  }

  /**
   * 后代联动：父选中（反选），子（除去disabled状态子）全选中（反选）
   */
  _toggleDescendantsSelection(source: any): void {
    if (!source) {
      return;
    }
    const selected = this.isSelected(source);
    _forEach(source.children, (item): void => {
      if (item.disabled) {
        return;
      }
      this._toggleSelection(item, selected);
      this._toggleDescendantsSelection(item);
    });
  }

  // renderdata 转换为map对象 NEED_DO: 和unfolddata有些冗余
  getRenderDataMap(data: TreeNode[], target?: any): Map<any, TreeNode> {
    let map = new Map();
    if (target) {
      map = target;
    }
    _forEach(data, (item): void => {
      map.set(this.result(item), item);
      if (item.children?.length) {
        this.getRenderDataMap(item.children, map);
      }
    });
    return map;
  }

  ngOnChanges(changes: SimpleChanges): void {
    const dataChange = changes.lvData;
    const dataSourceChange = changes.lvDataSource;

    super.ngOnChanges(changes);

    if (dataChange || dataSourceChange) {
      this._unfoldData = new Map();
      this.setUnfoldData(dataChange.currentValue, this._unfoldData);
      this.initSelectionData();
    }
  }

  /**
   * 祖先联动：子切换，父判断是否子都全选（反选）改变选中状态
   */
  _toggleAncestorSelection(source: any): void {
    if (!source || source.disabled) {
      return;
    }
    const parentRow = this.getParentSelectionData(source);

    if (!parentRow || parentRow.disabled) {
      return;
    }
    const unselected = parentRow.children.some((item): boolean => !item.disabled && !this.isSelected(item));
    this._toggleSelection(parentRow, !unselected);
    this._toggleAncestorSelection(parentRow);
  }
}
